package org.xqp.user.service.impl;


import lombok.SneakyThrows;
import net.bytebuddy.implementation.auxiliary.AuxiliaryType;
import org.omg.CORBA.TIMEOUT;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.xqp.basic.exception.MyException;
import org.xqp.basic.util.SendMsg;
import org.xqp.basic.util.StrUtils;
import org.xqp.user.constant.UserConstant;
import org.xqp.user.domain.User;
import org.xqp.user.mapper.UserMapper;
import org.xqp.user.service.IVerifycodeService;

import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class VerifycodeServiceImpl implements IVerifycodeService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 这个方法是在判断是由注册发送的短信验证码还是绑定发送的短信验证码
     */
    @Override
    public void smsCode(Map<String,String> param) {
        // 获取到前台传过来的电话号码和类型
        String phone = param.get("phone");
        String type = param.get("type");
        // 判断
        // 1. 手机号和前端传过来判断是绑定还是注册的类型都不能为空
        if(StringUtils.isEmpty(phone) || StringUtils.isEmpty(type)){
            throw  new MyException("手机号和前端传过来判断是注册还是绑定的类型都不能为空");
        }
        String redisKey =null; // 准备账号储存在redis中的key

        if(type.equals("register")){ // 如果type是register  那么就是注册
            // 判断手机号是否已存在  t_user
            User user = userMapper.querryByPhone(phone);
            if(user!=null){
                throw new MyException("手机号已注册。。。");
            }
            redisKey = UserConstant.REGISTER_PREFIX + phone; // 账号储存到redis中的key由我们自己写的常量前缀加上前端传过来的电话组成
            sendCode(redisKey); // 调用我们下面写的方法将redisKey传入继续进行验证发送短信
        }else if(type.equals("binder")){ // 如果type是binder  那么就是注册
            redisKey = UserConstant.BINDER_PREFIX + phone; // 账号储存到redis中的key由我们自己写的常量前缀加上前端传过来的电话组成
            sendCode(redisKey); // 调用我们下面写的方法将redisKey传入继续进行验证发送短信
        }
    }


    /**
     *
     * @param redisKey
     * 发送验证码的方法
     */
    public void sendCode(String redisKey) {

        // 判断验证码是否超出三分中，有没有过期， 从redis中取，如果能取到，没有过期  通过key获取到value   value就是验证码
        //  这是存入redis中的key: 业务标识+手机号    register_prefix+phone

        Object tmpCode = redisTemplate.opsForValue().get(redisKey);
        String code = null; // 先创建一个对象来装随机数
        if(tmpCode!=null){ // 获取到了验证码就证明验证码在三分钟以内继续进行判断
            // 3.1. 判断当前验证码是否超过一分钟，没有超过一分钟，直接提示：验证码已发送，请勿。。。
            // 获取时间戳   因为tmpCode是object所以要先转换为字符串在进行分割 这里我们的是用时间戳加上：号加上4位随机数来进行加密的而split方法是将字符串进行切割并放房进数组中所以
            // 所以我们以：作为切割的对象获取到数组  索引为0就是时间戳  索引为1就是随机数
            String time = tmpCode.toString().split(":")[0]; // 获取到时间戳
            /**
             * System.currentTimeMillis() 获取到当前时间的时间戳
             * Long.valueOf(time)  将time中的值装换为Long类型
             * 这样两个值是一个类型才能进行运算判断大小
             */
            if(System.currentTimeMillis()-Long.valueOf(time)<=60000){//用当前的时间戳 减 存放验证码时的时间戳 看是否<=60000毫秒也就是一分钟
                throw  new MyException("验证码已发送，请勿重复点击"); // 小于一分钟就不能让他重复点击获取按钮
            }else {
                // 3.2. 超过一分钟，重新刷新之前验证码的过期时间
                code = tmpCode.toString().split(":")[1];
            }
        }else { // 4.否者就证明验证码超过了三分钟就要重新生成验证码
            code = StrUtils.getComplexRandomString(4);
        }
        /**
         * 5.将获取到的验证码放入redis中
         * 第一个参数是key由业务标识和电话号码组成
         * 第二个参数是value是由时间戳加上：号加上验证码组成
         * 第三个参数是过期时间
         * 第四个参数是过期时间是分钟，秒还是小时
         */
        redisTemplate.opsForValue().set(redisKey,  System.currentTimeMillis()+":"+code, 3,  TimeUnit.MINUTES);
        // SendMsg.sendSMS(phone, "验证码:"+code+",请三分中内使用");
        // 6.调用我们写的工具类发送短信到电话号码
        //SendMsg.sendSMS(phone, "验证码:"+code+",请三分钟之内使用");
        System.out.println(code);
    }
}
